package com.guodi.common.utils;


import com.guodi.common.constant.StatusCode;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 手动校验实体
 * @author 陈宏成
 * @date 2021-12-28
 * */
public class ValidateUtil {

    // 非空分组1
    public interface NotBlankGroup{

    }
    // 非空分组2
    public interface NotBlankGroup2{

    }


    private ValidateUtil() {
    }

    /**
     * 验证器
     */
    private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    /**
     * 校验实体，返回实体所有属性的校验结果
     * @param objs 检验对象
     * @param groups 校验分组
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    public static <T> AjaxResult validateEntities(boolean throwException, List<T> objs, Class<?>... groups) {
        for (T obj : objs) {
            //解析校验结果
            Set<ConstraintViolation<T>> validateSet = validator.validate(obj,groups);
            AjaxResult ajaxResult = buildValidationResult(throwException, validateSet);
            if (Objects.nonNull(ajaxResult)){
                return ajaxResult;
            }
        }
        return null;
    }

    /**
     * 校验实体，返回实体所有属性的校验结果
     * @param obj 检验对象
     * @param groups 校验分组
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    public static <T> AjaxResult validateEntity(boolean throwException, T obj, Class<?>... groups) {
        //解析校验结果
        Set<ConstraintViolation<T>> validateSet = validator.validate(obj,groups);
        return buildValidationResult(throwException, validateSet);
    }

    /**
     * 校验实体，返回实体所有属性的校验结果
     * @param objs 检验对象
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    public static <T> AjaxResult validateEntities(boolean throwException, List<T> objs) {
        return validateEntities(throwException,objs, Default.class );
    }

    /**
     * 校验实体，返回实体所有属性的校验结果
     * @param obj 检验对象
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    public static <T> AjaxResult validateEntity(boolean throwException, T obj) {
        return validateEntity(throwException, obj, Default.class);
    }

    /**
     * 校验指定实体的指定属性是否存在异常
     * @param obj 检验对象
     * @param propertyName 要校验的属性名
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    public static<T> AjaxResult validateProperty(boolean throwException, T obj, String propertyName) {
        Set<ConstraintViolation<T>> validateSet = validator.validateProperty(obj, propertyName, Default.class);
        AjaxResult ajaxResult = buildValidationResult(throwException, validateSet);
        return ajaxResult;
    }

    /**
     * 将异常结果封装抛出异常，只抛第一个校验错误信息
     * @param validateSet 校验结果集
     * @param throwException 是否抛异常
     * @return null -- 正常通过，非null -- 存在错误，错误信息已放在AjaxResult中
     * @author 陈宏成
     * @date 2021-12-28
     */
    private static <T> AjaxResult buildValidationResult(boolean throwException, Set<ConstraintViolation<T>> validateSet) {
        AjaxResult validationResult = new AjaxResult();
        if (!CollectionUtils.isEmpty(validateSet)) {
            Iterator<ConstraintViolation<T>> iterator = validateSet.iterator();
            ConstraintViolation<T> violation = iterator.next();
            if (throwException == true){
                throw new RuntimeException(violation.getMessage());
            }else{
                return new AjaxResult(StatusCode.ERROR_CODE_40005, violation.getMessage());
            }
        }
        return null;
    }
}
